package com.huan.springcloud.extensionpoint.environmentpostprocessor;

import org.apache.commons.logging.Log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.*;

import java.util.HashMap;
import java.util.Map;

/**
 * <pre>
 * 可以使用该后置拦截器实现的功能
 *      1、配置属性的加解密
 *      2、删除配置文件的属性值
 *      3、添加属性值
 * 此处完成的功能：
 *      1、自定义一个 username 的属性值，并覆盖默认配置文件中的属性值
 *      2、日志的输出
 * 参考代码
 *      <a href="https://github.com/apolloconfig/apollo/blob/master/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java">https://github.com/apolloconfig/apollo/blob/master/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java</a><br/>
 *      <a href="https://github.com/apolloconfig/apollo/blob/master/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/PropertySourcesProcessor.java">https://github.com/apolloconfig/apollo/blob/master/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/PropertySourcesProcessor.java</a><br/>
 *      <a href="https://stackoverflow.com/questions/42839798/how-to-log-errors-in-a-environmentpostprocessor-execution">https://stackoverflow.com/questions/42839798/how-to-log-errors-in-a-environmentpostprocessor-execution</a><br/>
 * </pre>
 */
@Order(Ordered.LOWEST_PRECEDENCE)
public class CustomEnvironmentPostProcessor implements EnvironmentPostProcessor {
    private final String PROPERTY_SOURCE_NAME = "CUSTOMIZE_PROPERTY";

    private final Log log;

    /**
     * 使用这种方式是不会输出日志的，因为此时日志系统还为初始化，需要使用DeferredLog存日志，让后重放日志
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(CustomEnvironmentPostProcessor.class);

    /**
     * 从SpringBoot2.4开始就可以注入DeferredLogFactory对象，可以使用这个来输出日志
     */
    public CustomEnvironmentPostProcessor(DeferredLogFactory deferredLogFactory) {
        this.log = deferredLogFactory.getLog(CustomEnvironmentPostProcessor.class);
    }

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        if (environment.getPropertySources().contains(PROPERTY_SOURCE_NAME)) {
            log.info("该配置已经加入到了 Environment 中");
            return;
        }
        LOGGER.info("此日志无法输出");
        log.info("获取到配置文件中的 username 的值:" + environment.getProperty("username"));

        // 加入自定义的属性，覆盖掉默认配置文件中定义的
        Map<String, Object> properties = new HashMap<>(4);
        properties.put("username", "huan.fu");

        environment.getPropertySources().addFirst(new MapPropertySource(PROPERTY_SOURCE_NAME, properties));
        log.info("获取到配置文件中的 username 的值:" + environment.getProperty("username"));
    }
}

